package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"

	"github.com/songgao/water"
)

var (
	devicetypes = flag.String("device", "tun", "type of tuntap device ")
	tuntapip    = flag.String("ip", "10.0.0.1/24", "ip of tun/tap")
	kind        = flag.String("kind", "server", "is server or client")
	localaddre  = flag.String("local", "0.0.0.0:8001", "local server address")
	remoteaddre = flag.String("remote", "127.0.0.1:8001", "remote server address")
)

func init() {
	flag.Parse()
}

func main() {
	tuntapserver()
}

func tuntapserver() {
	// 选择tuntap类型，及设置配置
	config := water.Config{}
	switch *devicetypes {
	case "tap":
		config.DeviceType = water.TAP
	default:
		config.DeviceType = water.TUN
	}
	// 根据配置生成接口
	ifce, err := water.New(config)
	if err != nil {
		log.Fatal(err)
	}
	defer ifce.Close()
	err = setupNetDevice("addr", "add", *tuntapip, "dev", ifce.Name())
	if err != nil {
		fmt.Println("网卡[", ifce.Name(), "]设置网络地址失败：", err)
	} else {
		fmt.Println("网卡[", ifce.Name(), "]设置地址：", *tuntapip)
	}
	err = setupNetDevice("link", "set", ifce.Name(), "mtu", "1280", "up")
	if err != nil {
		fmt.Println("网卡[", ifce.Name(), "]启动失败：", err)
	} else {
		fmt.Println("网卡[", ifce.Name(), "]启动成功")
	}
	switch *kind {
	case "client":
		tcpclient(ifce)
	default:
		tcpserver(ifce)
	}
}

func tcpserver(ifio io.ReadWriter) {
	fmt.Println("the server is starting")
	listen, err := net.Listen("tcp", *localaddre)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			fmt.Println("accept failed, err:", err)
			continue
		}
		fmt.Println(conn.RemoteAddr(), "==>", conn.LocalAddr(), "[已连接]")
		go func() {
			buf := make([]byte, 1500)
			n, err := io.CopyBuffer(ifio, conn, buf)
			defer fmt.Println("data from client to device", n/1024, "kib")
			if err != nil {
				fmt.Println("data from client to device", err)
				return
			}
		}()
		go func() {
			buf := make([]byte, 1500)
			n, err := io.CopyBuffer(conn, ifio, buf)
			defer fmt.Println("data from device to client", n/1024, "kib")
			if err != nil {
				fmt.Println("data from device to client", err)
				return
			}
		}()
	}
}

func tcpclient(ifio io.ReadWriter) {
	fmt.Printf("the client is starting")
	conn, err := net.Dial("tcp", *remoteaddre)
	if err != nil {
		fmt.Println("dial failed, err", err)
		return
	}
	defer conn.Close()
	fmt.Println("[连接到]==>:", conn.RemoteAddr())
	go func() {
		buf := make([]byte, 1500)
		n, err := io.CopyBuffer(ifio, conn, buf)
		defer fmt.Println("data from server to device", n/1024, "kib")
		if err != nil {
			fmt.Println("data from server to device", err)
			return
		}
	}()
	func() {
		buf := make([]byte, 1500)
		n, err := io.CopyBuffer(conn, ifio, buf)
		defer fmt.Println("data from device to server", n/1024, "kib")
		if err != nil {
			fmt.Println("data from device to server", err)
			return
		}
	}()
}

func setupNetDevice(cmd ...string) error {
	cmdexec := exec.Command("ip", cmd...)
	cmdexec.Stderr = os.Stderr
	cmdexec.Stdout = os.Stdout
	err := cmdexec.Run()
	if err != nil {
		return err
	}
	return nil
}
